package org.example.erpapiservicespringmongoimpl;

import org.example.erpapicommon.Util.BasePage;
import org.example.erpapicommon.Util.Pageable;
import org.example.erpapicommon.Util.Param.*;
import org.example.erpapicommon.model.*;
import org.example.erpapicommon.service.OtherService;
import org.example.erpapiservicespringmongoimpl.doc.*;
import org.example.erpapiservicespringmongoimpl.mapper.*;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.data.mongodb.core.MongoTemplate;
import org.springframework.data.mongodb.core.query.Criteria;
import org.springframework.data.mongodb.core.query.Query;
import org.springframework.stereotype.Component;

import java.util.*;

@Component
public class OtherServiceMongoImpl implements OtherService {
    @Autowired
    MongoTemplate mongoTemplate;
    @Autowired
    EmployeeMapper employeeMapper;
    @Autowired
    CustomerMapper customerMapper;
    @Autowired
    ShipperMapper shipperMapper;
    @Autowired
    SupplierMapper supplierMapper;
    @Autowired
    StockMapper stockMapper;
    @Autowired
    CategoryMapper categoryMapper;
    @Override
    @Cacheable(value = "erp_api",key = "'pageEmployees_'+#param.toString()", condition = "#param != null")
    public Pageable<TEmployee> findEmployees(EmployeeQueryParam param) {
        List<Criteria> criteriaList =new ArrayList<>();
        String name = param.getName();
        if (name!=null&&!name.isBlank()){
            criteriaList.add(Criteria.where("name").regex(name));
        }
        String gender = param.getGender();
        if (gender!=null&&!gender.isBlank()){
            criteriaList.add(Criteria.where("gender").is(gender));
        }
        String region = param.getRegion();
        if (region!=null&&!region.isBlank()){
            criteriaList.add(Criteria.where("region").is(region));
        }
        String title = param.getTitle();
        if (title!=null&&!title.isBlank()){
            criteriaList.add(Criteria.where("title").is(title));
        }
        Query query = new Query();
        Criteria criteria = new Criteria();
        if (!criteriaList.isEmpty()){
            criteria.andOperator(criteriaList);
        }
        query.addCriteria(criteria);
        long totalCount = mongoTemplate.count(query, EmployeeDoc.class);
        int pageSize = param.getPageSize();
        int pageNumber = param.getPageNumber();
        int totalPage = PageUtil.getTotalPage((int)totalCount, pageSize);
        int offset = PageUtil.getOffset(pageNumber, pageSize);
        query.skip(offset).limit(pageSize);
        List<EmployeeDoc> employeeDocList = mongoTemplate.find(query, EmployeeDoc.class);
        List<TEmployee> tEmployeeList = employeeMapper.fromDocs(employeeDocList);
        BasePage<TEmployee> tEmployeePageable = new BasePage<>(tEmployeeList, pageNumber, pageSize, totalPage, (int)totalCount);
        return tEmployeePageable;
    }

    @Override
    @Cacheable(value = "erp_api",key = "'pageCustomers_'+#param.toString()", condition = "#param != null")
    public Pageable<TCustomer> findCustomers(CustomerQueryParam param) {
        List<Criteria> criteriaList =new ArrayList<>();
        String name = param.getName();
        if (name!=null&&!name.isBlank()){
            criteriaList.add(Criteria.where("name").regex(name));
        }
        String region = param.getRegion();
        if (region!=null&&!region.isBlank()){
            criteriaList.add(Criteria.where("region").is(region));
        }
        String province = param.getProvince();
        if (province!=null&&!province.isBlank()){
            criteriaList.add(Criteria.where("province").is(province));
        }
        String city = param.getCity();
        if (city!=null&&!city.isBlank()){
            criteriaList.add(Criteria.where("city").is(city));
        }
        Query query = new Query();
        Criteria criteria = new Criteria();
        if (!criteriaList.isEmpty()){
            criteria.andOperator(criteriaList);
        }
        query.addCriteria(criteria);
        long totalCount = mongoTemplate.count(query, CustomerDoc.class);
        int pageSize = param.getPageSize();
        int pageNumber = param.getPageNumber();
        int totalPage = PageUtil.getTotalPage((int)totalCount, pageSize);
        int offset = PageUtil.getOffset(pageNumber, pageSize);
        query.skip(offset).limit(pageSize);
       List<CustomerDoc> customerDocList = mongoTemplate.find(query, CustomerDoc.class);
        List<TCustomer> tCustomerList = customerMapper.fromDocs(customerDocList);
        BasePage<TCustomer> tCustomerPageable = new BasePage<>(tCustomerList, pageNumber, pageSize, totalPage, (int)totalCount);
        return tCustomerPageable;
    }

    @Override
    @Cacheable(value = "erp_api",key = "'pageShippers_'+#param.toString()", condition = "#param != null")
    public Pageable<TShipper> findShippers(ShipperQueryParam param) {
        List<Criteria> criteriaList =new ArrayList<>();
        String name = param.getName();
        if (name!=null&&!name.isBlank()){
            criteriaList.add(Criteria.where("name").regex(name));
        }
        Query query = new Query();
        Criteria criteria = new Criteria();
        if (!criteriaList.isEmpty()){
            criteria.andOperator(criteriaList);
        }
        query.addCriteria(criteria);
        long totalCount = mongoTemplate.count(query, ShipperDoc.class);
        int pageSize = param.getPageSize();
        int pageNumber = param.getPageNumber();
        int totalPage = PageUtil.getTotalPage((int)totalCount, pageSize);
        int offset = PageUtil.getOffset(pageNumber, pageSize);
        query.skip(offset).limit(pageSize);
        List<ShipperDoc> shipperDocList = mongoTemplate.find(query, ShipperDoc.class);
        List<TShipper> tShipperList = shipperMapper.fromDocList(shipperDocList);
        BasePage<TShipper> tShipperPageable = new BasePage<>(tShipperList, pageNumber, pageSize, totalPage, (int)totalCount);
        return tShipperPageable;
    }

    @Override
    @Cacheable(value = "erp_api",key = "'pageSuppliers_'+#param.toString()", condition = "#param != null")
    public Pageable<Supplier> findSuppliers(SupplierQueryParam param) {
        List<Criteria> criteriaList =new ArrayList<>();
        String name = param.getName();
        if (name!=null&&!name.isBlank()){
            criteriaList.add(Criteria.where("name").regex(name));
        }
        Query query = new Query();
        Criteria criteria = new Criteria();
        if (!criteriaList.isEmpty()){
            criteria.andOperator(criteriaList);
        }
        query.addCriteria(criteria);
        long totalCount = mongoTemplate.count(query, SupplierDoc.class);
        int pageSize = param.getPageSize();
        int pageNumber = param.getPageNumber();
        int totalPage = PageUtil.getTotalPage((int)totalCount, pageSize);
        int offset = PageUtil.getOffset(pageNumber, pageSize);
        query.skip(offset).limit(pageSize);
        List<SupplierDoc> supplierDocList = mongoTemplate.find(query, SupplierDoc.class);
        List<Supplier> tSupplierList = supplierMapper.fromListDoc(supplierDocList);
        BasePage<Supplier> tSupplierPageable = new BasePage<>(tSupplierList, pageNumber, pageSize, totalPage, (int)totalCount);
        return tSupplierPageable;
    }

    @Override
    @Cacheable(value = "erp_api",key = "'pageStocks_'+#param.toString()", condition = "#param != null")
    public Pageable<Stock> findPurchases(PurchaseQueryParam param) {
        List<Criteria> criteriaList =new ArrayList<>();
        String productName = param.getProductName();
        if (productName!=null&&!productName.isBlank()){
            criteriaList.add(Criteria.where("productName").regex(productName));
        }
        String supplierName = param.getSupplierName();
        if (supplierName!=null&&!supplierName.isBlank()){
            criteriaList.add(Criteria.where("supplierName").regex(supplierName));
        }
        Date startDate = param.getStartDate();
        if (startDate!=null){
            criteriaList.add(Criteria.where("purchaseDate").gte(startDate));
        }
        Date endDate = param.getEndDate();
        if (endDate!=null){
            criteriaList.add(Criteria.where("purchaseDate").lte(endDate));
        }
        Query query = new Query();
        Criteria criteria = new Criteria();
        if (!criteriaList.isEmpty()){
            criteria.andOperator(criteriaList);
        }
        query.addCriteria(criteria);
        long totalCount = mongoTemplate.count(query, StockDoc.class);
        int pageSize = param.getPageSize();
        int pageNumber = param.getPageNumber();
        int totalPage = PageUtil.getTotalPage((int)totalCount, pageSize);
        int offset = PageUtil.getOffset(pageNumber, pageSize);
        query.skip(offset).limit(pageSize);
        List<StockDoc> stockDocList = mongoTemplate.find(query, StockDoc.class);
        List<Stock> stockList = stockMapper.toStockList(stockDocList);
        BasePage<Stock> stockPageable = new BasePage<>(stockList, pageNumber, pageSize, totalPage, (int)totalCount);
        return stockPageable;
    }

    @Override
    @Cacheable(value = "erp_api",key = "'findCategoriesByLevel_'+#level")
    public List<TCategory> findCategoriesByLevel(Integer level) {
        List<CategoryDoc> categoryDocList = mongoTemplate.find(Query.query(Criteria.where("level").is(level)), CategoryDoc.class);
        List<TCategory> tCategoryList = categoryMapper.fromCategoriesToTCategories(categoryDocList);
        for(TCategory tCategory:tCategoryList){
            if(level==1){
                tCategory.setParentId("0");
            }else if(level==2){
                tCategory.setParentId(tCategory.getId().substring(0,1));
            }else{
                tCategory.setParentId(tCategory.getId().substring(0,3));
            }
        }
        return tCategoryList;
    }

}
